package com.ias.agdis_r.netservice;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.TimeoutException;

import android.content.Context;
import android.os.Handler;

import com.ias.agdis_r.R;
import com.ias.agdis_r.manager.DataBaseManager;
import com.ias.agdis_r.manager.EffectManager;
import com.ias.agdis_r.manager.MessageManager;
import com.ias.agdis_r.manager.ThreadManager;
import com.ias.agdis_r.netservice.actions.PrivateNetService;
import com.ias.agdis_r.util.S;
import com.ias.agdis_r.util.TestUtil;
import com.ias.agdis_r.util.sdcard.WriteLog;

/**
 * 服务基类
 * 
 * @author wanghu
 * 
 */
public abstract class BaseService {

	protected Handler myHandler = null;
	protected Context context;
	private Selector selector;
	protected SocketChannel socketChannel;
	private ReceiveMessageThread recMsg;
	private boolean isConnected = false;
	// SOCKET是否结束连接状态
	private boolean finishConnect = true;
	private boolean checkAvailableFlag = true;
	private CheckAvailableThread checkAvailableThread = null;
	private static final int socketChannel_TIMEOUT = 30000; // socket超时时间
	public int connectCount = 0;

	public BaseService(Handler handler, Context context) {
		this.myHandler = handler;
		this.context = context;
	}

	public void close() {
		if (isConnected) {
			if (recMsg != null){
				recMsg.closeRun();
				recMsg =null;
			}
			//如果不存在本机IP地址，或本机IP地址为0.0.0.0
			if(!hasLocalAddress())
			{
				//Header.getInstance().sendHeaderBroadcast(NetUtils.SENDNETSTATUS,NetUtils.GETADDRESS_FAILED,this);
			}
			else
			{
				//Header.getInstance().sendHeaderBroadcast(NetUtils.SENDNETSTATUS,NetUtils.GETADDRESS_SUCCESS,this);
			}
			try {
				if (socketChannel != null) {
					WriteLog.getInstance().writeLog("关闭SOCKET(SOCKET断开)");
					Socket socket = socketChannel.socket();
					if(socket!=null){
						socket.close();
					}
					socketChannel.close();
					socketChannel = null;
				}
				if(BaseService.this.selector!=null){
					BaseService.this.selector.close();
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				WriteLog.getInstance().writeLog("SOCKET关闭异常:"+e.getMessage());
			}
			isConnected = false;
			//保存LCT信息
			this.setLastLCT(S.getNowTime());
		}
	}

	public boolean hasLocalAddress() {
		if (S.isNotEmpty(getLocalIpAddress())
				&& !"0.0.0.0".equals(getLocalIpAddress())) {
			// Header.getInstance().sendHeaderBroadcast(NetUtils.SENDNETSTATUS,
			// NetUtils.GETADDRESS_SUCCESS,this);
			return true;
		} else {
			// Header.getInstance().sendHeaderBroadcast(NetUtils.SENDNETSTATUS,
			// NetUtils.GETADDRESS_FAILED,this);
			return false;
		}
	}

	public boolean hasLocalAddress2() {
		if (S.isNotEmpty(getLocalIpAddress())
				&& !"0.0.0.0".equals(getLocalIpAddress())) {
			return true;
		} else {
			return false;
		}
	}

	protected ArrayList<HashMap<String, Object>> getWifiList() {
		return null;
	};

	public abstract String getLocalIpAddress();

	// 获取本机SOCKET端口
	public abstract int getLocalSocketPort();

	// 设置本机SOCKET端口
	public abstract void setLocalSocketPort(int port);

	// 设置本机SOCKET IP地址
	public abstract void setLocalSocketIp(String localSocket);

	// 获取本机SOCKET IP地址
	public abstract String getLocalSocketIp();

	protected String getString(int resId) {
		return context.getString(resId);
	}

	public abstract String getPushIP();
	
	public abstract String getRestfulIP();

	/** 连接Socket，并发送当前状态 **/
	public Boolean connectSocket() {
		boolean isconnected = true;
		finishConnect = false;
		try {
			String ip = getPushIP();
			int port = getPushPort();
			createSocketChannel(ip, port);
			isConnected = true;
			// Header.getInstance().sendHeaderBroadcast(NetUtils.SENDNETSTATUS,
			// NetUtils.CONN_SUCCESS,this);
			// 保存最后连接SOKET时间
			this.setLastCCT(S.getNowTime());
			// 发送测试SGOC消息
			sendTestSGOCMessage(TestUtil.TAG_1);
			ThreadManager.getInstance().startHeartThread();// 启动心跳
			ThreadManager.getInstance().clearCounter(this);
			ThreadManager.getInstance().sysTimeCounter(this);
		} catch (SocketException e) {
			isconnected = false;
			isConnected = false;
			finishConnect = true;
			connectError(e);
		} catch (IOException e) {
			isconnected = false;
			isConnected = false;
			finishConnect = true;
			connectError(e);
		} catch (NullPointerException e) {
			isconnected = false;
			isConnected = false;
			finishConnect = true;
			connectError(e);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			isconnected = false;
			isConnected = false;
			finishConnect = true;
			connectError(e);
		}
		finishConnect = true;
		return isconnected;
	}

	/***
	 * socket 出现异常
	 * **/
	private void connectError(Exception e) {
		e.printStackTrace();
		WriteLog.getInstance().writeLog("SOCKET连接错误:"+e.getMessage());
		try {
			WriteLog.getInstance().writeLog("关闭SOCKET(连接失败)");
			if (recMsg != null){
				recMsg.closeRun();
				recMsg =null;
			}
			if(socketChannel!=null){
				socketChannel.close();
				Socket socket = socketChannel.socket();
				if(socket!=null){
					socket.close();
				}
				socketChannel = null;
			}
			if(BaseService.this.selector!=null){
				BaseService.this.selector.close();
			}

		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			WriteLog.getInstance().writeLog("SOCKET关闭异常:"+e1.getMessage());
		}

	}

	private void createSocketChannel(String hostName, int port)
			throws IOException, TimeoutException {

		synchronized (this) {
			if (isConnected) {
				return;
			}
			connectCount++;

			WriteLog.getInstance().writeLog(
					this.getClass().getSimpleName() + context.getString(R.string.BS_2) + hostName
							+ "|port:" + port + context.getString(R.string.BS_3) + connectCount);
			EffectManager.getInstance().ttsPlay(
					EffectManager.TTS_TYPE_TEMP,
					this.getClass().getSimpleName() + context.getString(R.string.BS_4)
							+ connectCount, false);
			// socketChannel = SocketChannel.open(new
			// InetSocketAddress(hostName, port));
			socketChannel = SocketChannel.open();
			socketChannel.socket().setSoTimeout(socketChannel_TIMEOUT);
			socketChannel.configureBlocking(false);// 设置socket为非阻塞
			socketChannel.socket().setKeepAlive(true);
			//解析域名或IP地址
			InetAddress inetAddress = InetAddress.getByName(hostName);
			//SOCKET绑定IP地址
			socketChannel.connect(new InetSocketAddress(inetAddress.getHostAddress(), port));
			// SOCKET绑定IP地址
//			socketChannel.connect(new InetSocketAddress(hostName, port));
			for (int i = 0; !socketChannel.finishConnect() && i < 30; i++) {
				try {
					Thread.sleep(1 * 1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			// 如果SOCKET没有结束连接
			if (!socketChannel.finishConnect()) {
				// 如果还未结束连接,关闭socketChannel,抛出TimeoutException
				if (socketChannel != null) {
					socketChannel.close();
					socketChannel = null;
				}
				WriteLog.getInstance().writeLog(context.getString(R.string.BS_5));
				throw new TimeoutException();
			}
			// SOCKET本机地址
			String hostIp = getHostIp();
			// 如果SOCKET未连接成功，抛出SOCKET异常
			if (!socketChannel.socket().isConnected()
					|| socketChannel.socket().isClosed() || S.isEmpty(hostIp)
					|| hostIp.equals("0.0.0.0")
					|| S.isEmpty(getLocalIpAddress())
					|| ("0.0.0.0").equals(getLocalIpAddress())) {
				WriteLog.getInstance().writeLog(
						context.getString(R.string.BS_6)
								+ getLocalIpAddress() + ",hostIp=" + hostIp);
				throw new SocketException();
			}
			selector = Selector.open();
			socketChannel.register(selector, SelectionKey.OP_READ);
			recMsg = new ReceiveMessageThread(this);
			// 设置SOCKET地址
			setLocalSocketPort(socketChannel.socket().getLocalPort());
			setLocalSocketIp(hostIp);
			WriteLog.getInstance().writeLog(
					this.getClass().getSimpleName() + context.getString(R.string.BS_7) + hostName
							+ ":" + port + context.getString(R.string.BS_8) + hostIp + ":"
							+ getLocalSocketPort());
			EffectManager.getInstance().ttsPlay(
					EffectManager.TTS_TYPE_TEMP,
					this.getClass().getSimpleName() + context.getString(R.string.BS_7) + hostName
							+ ":" + port + context.getString(R.string.BS_8) + hostIp + ":"
							+ getLocalSocketPort(), false);
		}
	}

	private String getHostIp() {
		String result = "";
		InetAddress localAddress;
		Socket socket = socketChannel.socket();
		if (socket != null) {
			localAddress = socketChannel.socket().getLocalAddress();
			if (localAddress != null) {
				result = localAddress.getHostAddress();
			}
		}
		if (this.getClass().equals(PrivateNetService.class)) {
			result = getLocalIpAddress();
		}
		return result;
	}

	public boolean connectting() {
		return false;
	}

	/**
	 * 检测是否可用
	 */
	public void checkAvailable() {

		if (checkAvailableFlag) {
			checkAvailableFlag = false;
			checkAvailableThread = new CheckAvailableThread();
			checkAvailableThread.start();
		}

	}

	public boolean finishConnect() {
		return finishConnect;
	}

	/**
	 * 检测网络是否可用线程
	 */
	class CheckAvailableThread extends Thread {
		@Override
		public void run() {

			// 如果SOCKET未连接 且 如果已经结束SOCKET连接动作
			if (!isConnected() && finishConnect()) {
				if (hasLocalAddress()) { // 如果能获取到IP和路由信息
					// 连接SOCKET
					// 必须用BASE或TEMP否则会因只用吐司时启动后很快异常挂掉
					EffectManager.getInstance().ttsPlay(
							EffectManager.TTS_TYPE_TEMP, context.getString(R.string.BS_9), false);
					connectSocket();
				} else {
					close();
				}
			}
			checkAvailableFlag = true;
		}
	}

	/**
	 * 发送信息
	 *
	 * @return
	 * @throws IOException
	 * @throws IOException
	 */
	public void sendTestSGOCMessage(int tab) throws IOException {

		String msg = MessageManager.getInstance().getTestSGOCMessage(tab,
				getLastCCT(), getLastLCT(),
				getLocalSocketIp() + ":" + getLocalSocketPort(), null);
		// 发送TestSGOC消息
		sendMessage(msg);
	}

	/**
	 * 发送信息
	 * 
	 * @param msg
	 *            要发送的消息
	 * @return
	 * @throws IOException
	 * @throws IOException
	 */
	public void sendMessage(String msg) throws IOException {

		System.out.println("发送消息：" + msg);
		// 1.如果本机IP地址非空，
		// 2.SOCKET IP地址非空，
		// 3.本机IP地址与SOCKET IP地址匹配
		// 发送消息
		if (S.isNotEmpty(getLocalIpAddress())
				&& S.isNotEmpty(getLocalSocketIp())
				&& getLocalIpAddress().indexOf(getLocalSocketIp()) > -1) {
			if (S.isNotEmpty(msg)) {
				byte[] messageByte = msg.getBytes("GBK"); // 将message转换成byte
				ByteBuffer writeBuffer = ByteBuffer
						.allocateDirect(messageByte.length);
				writeBuffer.put(messageByte);
				writeBuffer.flip();
				try{
					if (socketChannel != null && socketChannel.socket() != null
							&& socketChannel.socket().isConnected()
							&& !socketChannel.socket().isClosed()) {
						socketChannel.write(writeBuffer);
						ThreadManager.getInstance().updateSendMsgTime(this);
					}
				}catch (Exception e){
					e.printStackTrace();
				}

				writeBuffer.clear();
				writeBuffer = null;
			}
		}
		// 否则关闭网络
		else {
			WriteLog.getInstance().writeLog(context.getString(R.string.BS_10));
			this.close();
		}

		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 获取指定服务socket的连接port
	 */
	protected abstract int getPushPort();

	/**
	 * 获取指定服务restful的连接port
	 */
	public abstract int getRestfulPort();

	/**
	 * 获取最后一次的重连成功的时间
	 */
	public abstract String getLastCCT();

	/**
	 * 获取最后一次的连接失效时间
	 */
	public abstract String getLastLCT();

	/**
	 * 设置最后一次的重连成功的时间
	 */
	public abstract void setLastCCT(String cct);

	/**
	 * 设置最后一次的连接失效时间
	 */
	public abstract void setLastLCT(String lct);

	public boolean isConnected() {
		return isConnected;
	}

	public Handler getMyHandler() {
		return myHandler;
	}

	public Selector getSelector() {
		return selector;
	}

	public abstract int getNetIndex();

	public abstract void setLocalAddress(String _sNetIP);
}
